home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / dt / sperm.zip / SPERMPLT.C < prev    next >
C/C++ Source or Header  |  1992-12-20  |  10KB  |  331 lines

  1. //
  2. // SPERMPLT - swimming sperm plotter
  3. //
  4. // Version 1.0 12/18/92 Copyright (C) 1992 Hutchins Software
  5. // Author: Edward Hutchins &:
  6. //
  7. // The animation guts from a freely distributable X program:
  8. // xsperm.c
  9. // Drew Olbrich, Febrary 1991
  10. // Note --  This code originally served as a demonstration
  11. // of how to do animation under X.  The "guts" of the program
  12. // which draws the sperm are consequently located in one huge
  13. // chunk in the update_display() routine, and can be easily
  14. // cut out.
  15. // The animation function wrapped in a NeXTstep View subclass
  16. // by Ali Ozer, May 91
  17. // Very minor changes so this thing works as a screen saver module
  18. // by sam streeper, August 91
  19. // The "oneStep" method computes new locations.
  20. //
  21. // Revisions:
  22. // 12/18/92 ported to Windows as an SPX - Ed.
  23. //
  24.  
  25. #include <math.h>
  26. #include "sperm.h"
  27.  
  28. //
  29. // defines
  30. //
  31.  
  32. // fixed point scale factor
  33. #define VEC_1 (256L)
  34. #define NORM(x) ((INT)((x)/VEC_1))
  35.  
  36. typedef LONG VECTOR[2];
  37.  
  38. #define VEC_COPY( y, x )        y[0] = x[0], y[1] = x[1]
  39. #define VEC_ADD( z, x, y )      z[0] = x[0] + y[0], z[1] = x[1] + y[1]
  40. #define VEC_SUB( z, x, y )      z[0] = x[0] - y[0], z[1] = x[1] - y[1]
  41. #define VEC_MULT( x, a )        (x[0] = (x[0] * a) / VEC_1, x[1] = (x[1] * a) / VEC_1)
  42. #define VEC_DIV( x, a )         (x[0] = (x[0] * VEC_1) / a, x[1] = (x[1] * VEC_1) / a)
  43. #define VEC_ADDS( z, x, a, y )  (z[0] = x[0] + (((a)*y[0])/VEC_1), z[1] = x[1] + (((a)*y[1])/VEC_1))
  44. #define VEC_NORM( x )           { LONG _nLen = IntDist( x[0], x[1] ); VEC_DIV( x, _nLen ); }
  45.  
  46. #define MINRAD      (VEC_1 / 10)
  47. #define RADSTEP     2
  48. #define MAXRAD      (MINRAD * 6 * RADSTEP)
  49. #define INITRAD     (MINRAD * 3 * RADSTEP)
  50.  
  51. // RandInt(n) returns an integer 0..n-1
  52. #define RandInt(n) (arand( n ))
  53.  
  54. // degrees scaled to integer math
  55. #define DEGREE_SIZE 256
  56. #define DEGREE_MASK 255
  57. #define DEGREE_MAX 0x4000 // this is now hardcoded into the lookup table...
  58.  
  59. // faster than MulDiv!
  60. #define MULDEG(x,y) (((x)*(y))/DEGREE_MAX)
  61.  
  62. // DEG - convert an integer into a degree lookup index
  63. #define DEG(x) ((WORD)(x)&DEGREE_MASK)
  64.  
  65. //
  66. // imports
  67. //
  68.  
  69. IMPORT INT          nSpermCnt FROM( sperm.c );
  70. IMPORT TRI          triBlank FROM( sperm.c );
  71.  
  72. //
  73. // locals
  74. //
  75.  
  76. LOCAL DWORD         dwSeed;
  77. LOCAL VECTOR        x[SPERM_MAX], xPrev[SPERM_MAX];
  78. LOCAL VECTOR        v[SPERM_MAX];
  79. LOCAL VECTOR        lCenter;
  80. LOCAL LONG          lSin[SPERM_MAX];
  81. LOCAL LONG          lCos[SPERM_MAX];
  82. LOCAL LONG          lVel[SPERM_MAX];
  83. LOCAL LONG          lRad;
  84. LOCAL LONG          lDir;
  85. GLOBAL INT          nCos[DEGREE_SIZE] =
  86. {
  87.  16384,  16379,  16364,  16339,  16305,  16260,  16206,  16142,
  88.  16069,  15985,  15892,  15790,  15678,  15557,  15426,  15286,
  89.  15136,  14978,  14810,  14634,  14449,  14255,  14053,  13842,
  90.  13622,  13395,  13159,  12916,  12665,  12406,  12139,  11866,
  91.  11585,  11297,  11002,  10701,  10393,  10079,  9759,  9434,
  92.  9102,  8765,  8423,  8075,  7723,  7366,  7005,  6639,
  93.  6269,  5896,  5519,  5139,  4756,  4369,  3980,  3589,
  94.  3196,  2801,  2404,  2005,  1605,  1205,  803,  402,
  95.  0, -403, -804, -1206, -1606, -2006, -2405, -2802,
  96. -3197, -3590, -3981, -4370, -4757, -5140, -5520, -5897,
  97. -6270, -6640, -7006, -7367, -7724, -8076, -8424, -8766,
  98. -9103, -9435, -9760, -10080, -10394, -10702, -11003, -11298,
  99. -11586, -11867, -12140, -12407, -12666, -12917, -13160, -13396,
  100. -13623, -13843, -14054, -14256, -14450, -14635, -14811, -14979,
  101. -15137, -15287, -15427, -15558, -15679, -15791, -15893, -15986,
  102. -16070, -16143, -16207, -16261, -16306, -16340, -16365, -16380,
  103. -16384, -16380, -16365, -16340, -16306, -16261, -16207, -16143,
  104. -16070, -15986, -15893, -15791, -15679, -15558, -15427, -15287,
  105. -15137, -14979, -14811, -14635, -14450, -14256, -14054, -13843,
  106. -13623, -13396, -13160, -12917, -12666, -12407, -12140, -11867,
  107. -11586, -11298, -11003, -10702, -10394, -10080, -9760, -9435,
  108. -9103, -8766, -8424, -8076, -7724, -7367, -7006, -6640,
  109. -6270, -5897, -5520, -5140, -4757, -4370, -3981, -3590,
  110. -3197, -2802, -2405, -2006, -1606, -1206, -804, -403,
  111.  0,  402,  803,  1205,  1605,  2005,  2404,  2801,
  112.  3196,  3589,  3980,  4369,  4756,  5139,  5519,  5896,
  113.  6269,  6639,  7005,  7366,  7723,  8075,  8423,  8765,
  114.  9102,  9434,  9759,  10079,  10393,  10701,  11002,  11297,
  115.  11585,  11866,  12139,  12406,  12665,  12916,  13159,  13395,
  116.  13622,  13842,  14053,  14255,  14449,  14634,  14810,  14978,
  117.  15136,  15286,  15426,  15557,  15678,  15790,  15892,  15985,
  118.  16069,  16142,  16206,  16260,  16305,  16339,  16364,  16379
  119. };
  120. GLOBAL INT          nSin[DEGREE_SIZE] =
  121. {
  122.  0,  402,  803,  1205,  1605,  2005,  2404,  2801,
  123.  3196,  3589,  3980,  4369,  4756,  5139,  5519,  5896,
  124.  6269,  6639,  7005,  7366,  7723,  8075,  8423,  8765,
  125.  9102,  9434,  9759,  10079,  10393,  10701,  11002,  11297,
  126.  11585,  11866,  12139,  12406,  12665,  12916,  13159,  13395,
  127.  13622,  13842,  14053,  14255,  14449,  14634,  14810,  14978,
  128.  15136,  15286,  15426,  15557,  15678,  15790,  15892,  15985,
  129.  16069,  16142,  16206,  16260,  16305,  16339,  16364,  16379,
  130.  16383,  16379,  16364,  16339,  16305,  16260,  16206,  16142,
  131.  16069,  15985,  15892,  15790,  15678,  15557,  15426,  15286,
  132.  15136,  14978,  14810,  14634,  14449,  14255,  14053,  13842,
  133.  13622,  13395,  13159,  12916,  12665,  12406,  12139,  11866,
  134.  11585,  11297,  11002,  10701,  10393,  10079,  9759,  9434,
  135.  9102,  8765,  8423,  8075,  7723,  7366,  7005,  6639,
  136.  6269,  5896,  5519,  5139,  4756,  4369,  3980,  3589,
  137.  3196,  2801,  2404,  2005,  1605,  1205,  803,  402,
  138.  0, -403, -804, -1206, -1606, -2006, -2405, -2802,
  139. -3197, -3590, -3981, -4370, -4757, -5140, -5520, -5897,
  140. -6270, -6640, -7006, -7367, -7724, -8076, -8424, -8766,
  141. -9103, -9435, -9760, -10080, -10394, -10702, -11003, -11298,
  142. -11586, -11867, -12140, -12407, -12666, -12917, -13160, -13396,
  143. -13623, -13843, -14054, -14256, -14450, -14635, -14811, -14979,
  144. -15137, -15287, -15427, -15558, -15679, -15791, -15893, -15986,
  145. -16070, -16143, -16207, -16261, -16306, -16340, -16365, -16380,
  146. -16384, -16380, -16365, -16340, -16306, -16261, -16207, -16143,
  147. -16070, -15986, -15893, -15791, -15679, -15558, -15427, -15287,
  148. -15137, -14979, -14811, -14635, -14450, -14256, -14054, -13843,
  149. -13623, -13396, -13160, -12917, -12666, -12407, -12140, -11867,
  150. -11586, -11298, -11003, -10702, -10394, -10080, -9760, -9435,
  151. -9103, -8766, -8424, -8076, -7724, -7367, -7006, -6640,
  152. -6270, -5897, -5520, -5140, -4757, -4370, -3981, -3590,
  153. -3197, -2802, -2405, -2006, -1606, -1206, -804, -403
  154. };
  155.  
  156. //
  157. // arand - pseudorandom number from 0 to x-1
  158. //
  159.  
  160. LONG NEAR PASCAL arand( LONG x )
  161. {
  162.     dwSeed = dwSeed * 0x343fd + 0x269ec3;
  163.     return( (LONG)((dwSeed >> 8) % x) );
  164. }
  165.  
  166. //
  167. // IntDist - find an approximate distance
  168. //
  169.  
  170. LONG NEAR PASCAL IntDist( LONG dx, LONG dy )
  171. {
  172.     LONG            lDist;
  173.  
  174.     if (dx < 0) dx = -dx;
  175.     if (dy < 0) dy = -dy;
  176.     lDist = dx + dy - (((dx > dy) ? dy : dx) >> 1);
  177.     return( (lDist > 0) ? lDist : 1 );
  178. }
  179.  
  180. //
  181. // Tri - convert a tri-state into a boolean (unset == random)
  182. //
  183.  
  184. BOOL NEAR PASCAL Tri( TRI tri )
  185. {
  186.     switch (tri)
  187.     {
  188.     case TRI_FALSE:
  189.         return( FALSE );
  190.     case TRI_TRUE:
  191.         return( TRUE );
  192.     default:
  193.         return( (BOOL)arand( 2 ) );
  194.     }
  195. }
  196.  
  197. //
  198. // DoEffect - do a special effect
  199. //
  200.  
  201. VOID NEAR PASCAL DoEffect( INT nVal )
  202. {
  203.     INT             i;
  204.  
  205.     switch (nVal)
  206.     {
  207.     case 0:
  208.         lDir *= -1;
  209.         for (i = 0; i < nSpermCnt; i++)
  210.         {
  211.             VECTOR y;
  212.             VEC_COPY( y, v[i] );
  213.             if (lDir < 0) v[i][0] = y[1], v[i][1] = -y[0];
  214.             else v[i][0] = -y[1], v[i][1] = y[0];
  215.         }
  216.         break;
  217.     case 1:
  218.         for (i = 0; i < nSpermCnt; i++) v[i][0] = -v[i][0];
  219.         break;
  220.     case 2:
  221.         for (i = 0; i < nSpermCnt; i++) v[i][1] = -v[i][1];
  222.         break;
  223.     case 3:
  224.         DoEffect( 1 );
  225.         DoEffect( 2 );
  226.         break;
  227.     case 4:
  228.         DoEffect( 0 );
  229.         DoEffect( 3 );
  230.     case 5:
  231.         lRad = lRad * RADSTEP;
  232.         if (lRad > MAXRAD) lRad = MAXRAD;
  233.         break;
  234.     case 6:
  235.         lRad = lRad / RADSTEP;
  236.         if (lRad < MINRAD) lRad = MINRAD;
  237.         break;
  238.     default:
  239.         break;
  240.     }
  241. }
  242.  
  243. //
  244. // SaverDraw - the main drawing routine
  245. //
  246.  
  247. VOID FAR PASCAL EXPORT SaverDraw( HWND hwnd, HDC hdc, HANDLE hinst,
  248.                                   BOOL (FAR PASCAL *lpfnYield)( VOID ) )
  249. {
  250.     INT             cx, cy, i;
  251.     INT             nRndCnt1, nRndCnt2;
  252.     RECT            rect;
  253.  
  254.     dwSeed += GetTickCount();
  255.  
  256.     GetWindowRect( hwnd, &rect );
  257.     cx = rect.right - rect.left;
  258.     cy = rect.bottom - rect.top;
  259.  
  260.     if (Tri( triBlank )) FillRect( hdc, &rect, GetStockBrush( BLACK_BRUSH ) );
  261.  
  262.     lDir = 1;
  263.     lRad = INITRAD;
  264.     if (nSpermCnt < 1) nSpermCnt = 1;
  265.     else if (nSpermCnt >= SPERM_MAX) nSpermCnt = SPERM_MAX - 1;
  266.     nRndCnt1 = 100;
  267.     nRndCnt2 = 200;
  268.     lCenter[0] = (cx / 2) * VEC_1;
  269.     lCenter[1] = (cy / 2) * VEC_1;
  270.  
  271.     for (i = 0; i < nSpermCnt; i++)
  272.     {
  273.         INT nAngle = (INT)RandInt( 10 ) + 5;
  274.         xPrev[i][0] = x[i][0] = RandInt( cx * VEC_1 );
  275.         xPrev[i][1] = x[i][1] = RandInt( cy * VEC_1 );
  276.         v[i][0] = RandInt( 256 * VEC_1 ) - 128 * VEC_1;
  277.         v[i][1] = RandInt( 256 * VEC_1 ) - 128 * VEC_1;
  278.         VEC_NORM( v[i] );
  279.         lSin[i] = nSin[ DEG(nAngle) ];
  280.         lCos[i] = nCos[ DEG(nAngle) ];
  281.         lVel[i] = RandInt( 4 * VEC_1 ) + 4 * VEC_1;
  282.     }
  283.  
  284.     while ((*lpfnYield)())
  285.     {
  286.         for (i = 0; i < nSpermCnt; i++)
  287.         {
  288.             VECTOR      w, y;
  289.             VECTOR      p;
  290.             VECTOR      xOld;
  291.             LONG        lTmp;
  292.  
  293.             VEC_COPY( xOld, xPrev[i] );
  294.             VEC_COPY( xPrev[i], x[i] );
  295.  
  296.             VEC_SUB( w, x[i], lCenter );
  297.             VEC_NORM( w );
  298.             VEC_COPY( y, w );
  299.             w[0] = MULDEG( y[0], lCos[i] ) - (lDir * MULDEG( y[1], lSin[i] )) / VEC_1;
  300.             w[1] = MULDEG( y[1], lCos[i] ) + (lDir * MULDEG( y[0], lSin[i] )) / VEC_1;
  301.             lTmp = (lRad * (160 * VEC_1 - lVel[i] * 20)) / VEC_1;
  302.             VEC_ADDS( p, lCenter, lTmp, w );
  303.             VEC_SUB( w, p, x[i] );
  304.             VEC_NORM( w );
  305.             VEC_ADD( v[i], v[i], w );
  306.             VEC_NORM( v[i] );
  307.             VEC_MULT( v[i], lVel[i] );
  308.             VEC_ADD( x[i], x[i], v[i] );
  309.  
  310.             SelectObject( hdc, GetStockPen( BLACK_PEN ) );
  311.             MoveTo( hdc, NORM( xOld[0] ), NORM( xOld[1] ) );
  312.             LineTo( hdc, NORM( xPrev[i][0] ), NORM( xPrev[i][1] ) );
  313.             SelectObject( hdc, GetStockPen( WHITE_PEN ) );
  314.             LineTo( hdc, NORM( x[i][0] ), NORM( x[i][1] ) );
  315.         }
  316.  
  317.         if (--nRndCnt1 < 0)
  318.         {
  319.             nRndCnt1 = (INT)RandInt( 700 );
  320.             lCenter[0] = RandInt( cx * VEC_1 );
  321.             lCenter[1] = RandInt( cy * VEC_1 );
  322.         }
  323.  
  324.         if (--nRndCnt2 < 0)
  325.         {
  326.             nRndCnt2 = (INT)RandInt( 600 );
  327.             DoEffect( nRndCnt2 % 7 );
  328.         }
  329.     }
  330. }
  331.